define(['knockout', 'util', 'store', 'config', 'knockout-file-bindings'], function (ko, Util, Store, Config) {
    function ViewModel(params) {
        Util.extend(this, params);
        var scope = this;

        //the function not in params it init in child class
        if (!scope.onFieldBlur) scope.onFieldBlur = function () {
        };

        scope._id = 'form_{0}'.formatTpl(Util.uuid(8, 16))
        //store the form id for clear was-validate css if necessary
        scope.record._formId = scope._id;
        //the update operation will get a new record from server
        //we need hide the form until the ajax request is finish
        scope._showForm = ko.observable(false);
        scope._fieldSets = [];
        //the _buttons will show at the bottom of the form if the showButtons is true
        scope._showButtons = scope.showButtons ? true : false;
        scope._buttons = ko.observableArray();
        scope._onButtonClick = function () {
            console.log('AForm:click callback not assign in child class')
        };
        scope._onModelChange = function (field) {
            if (scope.onModelChange) scope.onModelChange(field);
        };
        //the buttons can show under a form when not in a modal
        if (scope._showButtons && scope.buttons) {
            scope._buttons(scope.buttons);

            if (scope.onButtonClick) scope._onButtonClick = scope.onButtonClick;
        }
        //the button can add to a modal parent's bottom
        if (scope.buttons && scope._parent && scope._parent._name == 'modal') {
            scope._parent._buttons(scope.buttons);
            scope._parent.commit = scope.onButtonClick;
        }

        if (scope.record.id() == Config.modelDefaultId || !ko.root.mobile) {
            initFields();
            scope._showForm(true);
        } else {//only for mobile view and edit
            Util.ajaxGet(
                {
                    url: Util.generateUrl(scope.record.getProxy()) + '/' + scope.record.id(),
                    data: scope.record.ajaxWithQuery ? scope.record._query : {},
                    callback: function (data) {
                        if (data.success) {
                            scope.record._fullRecord = ko.root.storeCache[scope.record._storeId].createModelFormOBJ(data.data);
                            scope.record._fullRecord._formId = scope._id;
                            scope.record = scope.record._fullRecord;
                            initFields();
                            scope._showForm(true);
                        }
                    }
                });
        }

        function initFields() {
            if (scope.fields) {
                scope.fieldSets = [{name: '', fields: scope.fields}];
            }

            if (scope.fieldSets && scope.fieldSets.length > 0) {
                scope.fieldSets.forEach(function (fieldSet) {
                    scope._fieldSets.push({name: fieldSet.name, _fields: []});

                    if (fieldSet.fields) {
                        fieldSet.fields.forEach(function (field) {
                            var modelField;

                            if (field instanceof Object) {
                                modelField = scope.record.getField(field.name);

                                if (modelField) $.extend(modelField, field);
                            } else {
                                modelField = scope.record.getField(field);
                            }

                            if (modelField) {
                                modelField._colCss = {};//change form layout
                                modelField._labelCss = {};//a child form field label css
                                modelField._inputCss = {};//a child form field input css
                                //set the label direction
                                modelField._labelCss['text-sm-' + (scope.labelDirection ? scope.labelDirection : 'left')] = true;

                                if (modelField.col) {
                                    modelField._colCss['col-' + modelField.col] = true;
                                } else {
                                    modelField._colCss['col-12'] = true;
                                }

                                if (modelField.labelCol) {
                                    modelField._labelCss['col-sm-' + modelField.labelCol] = true;
                                    modelField._inputCss['col-sm-' + (12 - modelField.labelCol)] = true;
                                } else if (modelField.labelCol == 0) {
                                    modelField._labelCss['d-none'] = true;
                                    modelField._inputCss['col-sm-12'] = true;
                                } else {
                                    modelField._labelCss['col-sm-2'] = true;
                                    modelField._inputCss['col-sm-10'] = true;
                                }

                                modelField.isFormField = true;
                                scope._fieldSets[scope._fieldSets.length - 1]._fields.push(modelField);

                                switch (modelField.type) {
                                    case 'select':
                                        if (modelField.model) {
                                            var store = new Store({
                                                model: modelField.model,
                                                fixedQuery: modelField.fixedQuery,
                                                pageSize: 0,
                                                onLoadComplete: function () {
                                                    modelField.options(store.records());
                                                }
                                            });
                                        }
                                        break;
                                    case 'tree':
                                        modelField._customCmp = 'cmp:TreeField';
                                        break;
                                    case 'shuttle':
                                        modelField._customCmp = 'cmp:ShuttleField';
                                        break;
                                    case 'checkboxes':
                                        modelField._customCmp = 'cmp:CheckboxesField';
                                        break;
                                }
                                //for img preview
                                addFileListener(modelField);
                            }
                        });
                    }
                });
            }
        }

        function addFileListener(field) {
            if (field.preview && field.type == 'file') {
                if (field._mimeType == 'img') {
                    ko.computed(function () {
                        var file = scope.record[field.name].file == undefined ? null : scope.record[field.name].file();

                        if (file) {
                            var reader = new FileReader();

                            reader.onload = function (e) {
                                scope.record['_preview_' + field.name](e.target.result);
                            }

                            reader.readAsDataURL(file)
                        } else {
                            scope.record['_preview_' + field.name](scope.record[field.name.substr(0, field.name.length - 1)]());
                        }
                    });
                }
            }

            if (field.notify) {
                Util.koComputedDelay({
                    targetFun: function () {
                        if (field.type == 'file') {
                            if (scope.record[field.name].file) scope.record[field.name].file();
                        } else {
                            scope.record[field.name]();
                        }
                    }, callback: function () {
                        scope._onModelChange(field);
                    }
                });
            }
        }
    }

    ViewModel.prototype.isView = function (fieldName) {
        if (this.operation && this.operation.substr(0, 4) == 'view') {
            return true;
        }

        return this.record.isViewField(fieldName);
    }

    return ViewModel;
});
